/*
 * Copyright (c) 20202099 the original author or authors. All rights reserve.
 */
package org.tianyun.cloud.security.server;

import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.util.ArrayList;
import java.util.List;

/**
 * SecurityFilterChain构造器
 *
 * @auther ebert_chan
 */
public class SecurityFilterChainBuilder<T, U> {

    private List<SecurityFilter<T, U>> securityFilters;

    /**
     * 构建基于servlet的SecurityFilterChain
     *
     * @param securityFilters
     * @return
     * @auther ebert_chan
     */
    @SafeVarargs
    public static SecurityFilterChainBuilder<ServletRequest, ServletResponse> servlet(SecurityFilter<ServletRequest, ServletResponse>... securityFilters) {
        return chains(securityFilters);
    }

    /**
     * 构建基于spring web的SecurityFilterChain
     *
     * @param securityFilters
     * @return
     * @auther ebert_chan
     */
    @SafeVarargs
    public static SecurityFilterChainBuilder<ServerHttpRequest, ServerHttpResponse> gateway(SecurityFilter<ServerHttpRequest, ServerHttpResponse>... securityFilters) {
        return chains(securityFilters);
    }

    /**
     * 构建指定类型的过滤器链
     *
     * @param securityFilters
     * @return
     * @auther ebert_chan
     */
    @SafeVarargs
    public static <T, U> SecurityFilterChainBuilder<T, U> chains(SecurityFilter<T, U>... securityFilters) {
        SecurityFilterChainBuilder<T, U> builder = new SecurityFilterChainBuilder<T, U>();
        builder.securityFilters = new ArrayList<>();
        for (int i = 0; i < securityFilters.length; i++) {
            builder.securityFilters.add(securityFilters[i]);
        }
        return builder;
    }

    /**
     * 从尾部往过滤器链集合中添加一个SecurityFilter
     *
     * @param securityFilter
     * @return
     * @auther ebert_chan
     */
    public SecurityFilterChainBuilder<T, U> addSecurityFilter(SecurityFilter<T, U> securityFilter) {
        this.securityFilters.add(securityFilter);
        return this;
    }

    /**
     * 在指定位置往过滤器链集合中添加一个SecurityFilter
     *
     * @param index
     * @param securityFilter
     * @return
     * @auther ebert_chan
     */
    public SecurityFilterChainBuilder<T, U> addSecurityFilter(int index, SecurityFilter<T, U> securityFilter) {
        securityFilters.add(index, securityFilter);
        return this;
    }

    /**
     * 在指定过滤器前插入一个SecurityFilter
     *
     * @param beforeClass
     * @param securityFilter
     * @return
     * @auther ebert_chan
     */
    public SecurityFilterChainBuilder<T, U> addSecurityFilterBefore(Class<? extends SecurityFilter<T, U>> beforeClass, SecurityFilter<T, U> securityFilter) {
        int index = -1;
        for (int i = 0; i < securityFilters.size(); i++) {
            if (securityFilters.get(i).getClass().equals(beforeClass)) {
                index = Math.max(i - 1, 0);
                break;
            }
        }
        if (index < 0) {
            throw new IllegalArgumentException("SecurityFilter \"" + beforeClass.getName() + "\" does not exist");
        }
        this.addSecurityFilter(index, securityFilter);
        return this;
    }

    /**
     * 在指定过滤器后插入一个SecurityFilter
     *
     * @param afterClass
     * @param securityFilter
     * @return
     * @auther ebert_chan
     */
    public SecurityFilterChainBuilder<T, U> addSecurityFilterAfter(Class<? extends SecurityFilter<T, U>> afterClass, SecurityFilter<T, U> securityFilter) {
        int index = -1;
        for (int i = 0; i < securityFilters.size(); i++) {
            if (securityFilters.get(i).getClass().equals(afterClass)) {
                index = i + 1;
                break;
            }
        }
        if (index < 0) {
            throw new IllegalArgumentException("SecurityFilter \"" + afterClass.getName() + "\" does not exist");
        }
        this.addSecurityFilter(index, securityFilter);
        return this;
    }

    /**
     * 构建并返回SecurityFilterChain
     *
     * @return
     * @auther ebert_chan
     */
    public SecurityFilterChain<T, U> build() {
        DefaultSecurityFilterChain<T, U> chain = new DefaultSecurityFilterChain<T, U>(securityFilters);
        return chain;
    }

}
